package models

import (
	"fmt"
	//"time"
	"encoding/json"
	"runtime/debug"
	"strconv"

	"../global"
	"github.com/astaxie/beego/logs"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
)

type ActionLog struct {
	Uid       uint32 `json:"user_id"`
	Zid       uint32 `json:"zid"`
	BigPlat   uint32 `json:"bigplat"`
	ChannelId uint32 `json:"channel_id"`
	ItemClass uint32 `json:"item_class"`
	ItemBeCnt int32 `json:"item_before_op_cnt"`
	ItemOpCnt uint32 `json:"item_op_cnt"`
	Time      uint32 `json:"time"`
	NickName  string `json:"nickname"`
	Platid    string `json:"platid"`
	SubPlat   string `json:"subplat"`
	OpType    string `json:"op_type"`
	SubType   string `json:"sub_type"`
	ItemPos   string `json:"item_pos"`
	ItemId    string `json:"item_id"`
	Date      string `json:"date"`
	Deviceid  string `json:"deviceid"`
}

const (
	DAY = 86400
)

var (
	actO      orm.Ormer
	mapRawPre map[string]orm.RawPreparer = make(map[string]orm.RawPreparer) // key:date val:RawPre
)

func ActInit() {
	actO = orm.NewOrm()
}

func actTryCreateTb(name string) {
	if name == "" {
		fmt.Println("ActionLog craete table is empty")
		debug.PrintStack()
		return
	}
	sql := fmt.Sprintf(
		"CREATE TABLE IF NOT EXISTS `%s`"+`(
            id int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增id',
            uid int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '玩家唯一uid',
            zid int(11) NOT NULL DEFAULT 0 COMMENT '服务器id',
            nickname varchar(128) NOT NULL DEFAULT '' COMMENT '玩家名字',
            platid varchar(64) NOT NULL DEFAULT '' COMMENT 'big平台名称',
            subplat varchar(64) NOT NULL DEFAULT '' COMMENT '子渠道名称',
            bigplat int(11) NOT NULL DEFAULT 0 COMMENT 'big平台id',
            channel_id int(11) NOT NULL DEFAULT 0 COMMENT '子渠道id',
            item_class int(11) NOT NULL DEFAULT 0 COMMENT '操作唯一id',
            op_type varchar(128) NOT NULL DEFAULT '' COMMENT '操作名称',
            sub_type varchar(64) NOT NULL DEFAULT '' COMMENT '货币类型',
            item_pos varchar(64) NOT NULL DEFAULT '' COMMENT '道具类型',
            item_id varchar(64) NOT NULL DEFAULT '' COMMENT '道具id',
            item_be_cnt int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '道具使用之前数量',
            item_op_cnt int(11) NOT NULL DEFAULT 0 COMMENT '道具操作数量',
            time int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '时间戳',
            date varchar(32) NOT NULL DEFAULT '' COMMENT '日期',
            deviceid varchar(64) NOT NULL DEFAULT '' COMMENT '设备id',
            exinfo text NOT NULL,
            PRIMARY KEY (id),
            KEY uid (uid),
            KEY nickname (nickname),
            KEY zid (zid),
            KEY time (time)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`, name)
	res, err := actO.Raw(sql).Exec()
	if err == nil {
		num, _ := res.RowsAffected()
		fmt.Println("mysql row affected nums: ", num)
	} else {
		fmt.Println("mysql exec error", err)
		panic("create table error" + name)
	}
}

func genAInsertSqlSmt(nowDate string) orm.RawPreparer {
	var insertSql string = "INSERT INTO `" + nowDate + "`(uid,zid,nickname,platid,subplat,bigplat,channel_id,item_class," +
		`op_type,sub_type,item_pos,item_id,item_be_cnt,item_op_cnt,time,date,deviceid,exinfo)
                            VALUES(?, ?, ?, ?, ?, ?, ?, ?, 
                            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
	var o orm.Ormer = orm.NewOrm()
	pre, err := o.Raw(insertSql).Prepare()
	if nil != err {
		fmt.Println("action insert actStatmetSql error", err)
		panic("action prepare error")
	}
	return pre
}

func getRawPreByDate(date string) orm.RawPreparer {
	pre, ok := mapRawPre[date]
	if ok {
		return pre
	} else {
		actTryCreateTb(date)
		pre = genAInsertSqlSmt(date)
		mapRawPre[date] = pre
		return pre
	}
}

//新一天回收不用的stmt
func CheckNewDay() {
	//println("len mapRawPre", len(mapRawPre))
	maxRawPre, erratoi := strconv.Atoi(global.Config["maxRawPre"])
	if nil != erratoi {
		maxRawPre = 3 //default value
	}
	if len(mapRawPre) > maxRawPre {
		var rmdate string
		var pre orm.RawPreparer
		for k, v := range mapRawPre {
			if rmdate == "" {
				rmdate = k
				pre = v
			} else if rmdate > k {
				rmdate = k
				pre = v
			}
		}
		if nil != pre {
			err := pre.Close()
			if nil != err {
				logs.Warn("actPre close error", err)
			}
			delete(mapRawPre, rmdate)
		}
	}
	/*
	   t := time.Now()
	   now := t.Unix()
	   if now >= daytime {
	       daytime = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()).Unix() + DAY
	       lastdate = t.Format("2006-01-02")
	       err := actPre.Close()
	       if nil != err {
	           logs.Warn("actPre close error", err)
	       }
	       //actTryCreateTb(lastdate)
	       //genAInsertSqlSmt(lastdate)
	   }
	*/
}

func CallActInsert(data string) {
	var alog ActionLog
	errs := json.Unmarshal([]byte(data), &alog)
	if errs != nil {
		fmt.Println("json unmarshal error:", errs)
	} else {
		actPre := getRawPreByDate(alog.Date)
		_, err := actPre.Exec(alog.Uid, alog.Zid, alog.NickName, alog.Platid, alog.SubPlat, alog.BigPlat, alog.ChannelId,
			alog.ItemClass, alog.OpType, alog.SubType, alog.ItemPos, alog.ItemId, alog.ItemBeCnt, alog.ItemOpCnt,
			alog.Time, alog.Date, alog.Deviceid, "")
		if err != nil {
			fmt.Println("actPre Exec error:", err)
		} else {
			//fmt.Println("actPre Exec success")
			//logs.Debug("actPre Exec success")
		}
	}
}
